package cn.wsalix.admin.service.impl;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Observable;

import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.anlaser.admin.BaseUser;
import cn.anlaser.service.impl.CommonServiceImpl;
import cn.anlaser.utils.SearchFilter;
import cn.anlaser.utils.SearchFilter.Operator;
import cn.wsalix.admin.entity.SysRole;
import cn.wsalix.admin.entity.SysUser;
import cn.wsalix.admin.form.UserForm;
import cn.wsalix.admin.init.UserInit;
import cn.wsalix.admin.repository.UserRepository;
import cn.wsalix.admin.service.UserService;
import cn.wsalix.config.AppConfig;
import cn.wsalix.constant.Global;
import cn.wsalix.exception.UserException;
import cn.wsalix.login.entity.QQUser;
import cn.wsalix.login.service.QQUserService;
import cn.wsalix.observable.service.LoginService;
import cn.wsalix.observable.service.RegisterService;
import cn.wsalix.shiro.credentials.RetryLimitHashedCredentialsMatcher;
import cn.wsalix.shiro.token.QQToken;
import cn.wsalix.shiro.token.WxAppToken;
import cn.wsalix.sys.service.VerifyCodeService;
import cn.wsalix.type.UserRegTypeEnum;
import cn.wsalix.user.service.UserCenterService;
import cn.wsalix.user.service.UserInfoService;
import cn.wsalix.utils.UserUtils;
import cn.wsalix.utils.Utils;
import cn.wsalix.weixin.entity.WxUser;
import cn.wsalix.weixin.service.WxUserService;

@Service("userService")
public class UserServiceImpl extends
		CommonServiceImpl<UserForm, UserRepository, SysUser> implements
		UserService {
	@Autowired
	private UserRepository userRepository;
	@Autowired
	protected UserException userException;
	@Autowired
	protected UserUtils userUtils;
	@Autowired
	private UserInit userInit;
	@Autowired
	private Utils utils;
	@Autowired
	private AppConfig appConfig;
	@Autowired
	private VerifyCodeService verifyCodeService;
	@Autowired
	private QQUserService qqUserService;
	@Autowired
	private WxUserService wxUserService;
	@Autowired
	private UserInfoService userInfoService;
	@Autowired
	private UserCenterService userCenterService;

	@Override
	public UserRepository getRepository() {
		return userRepository;
	}

	@Override
	public String module() {
		return "/admin/user";
	}

	@Cacheable(value = "accountCache", key = "#id")
	@Override
	public SysUser findById(Long id) {
		SysUser user = super.findById(id);
		if (user == null) {
			return null;
		}
		if (user.getUserInfo() == null) {
			user.setUserInfo(userInfoService.findByUser(user));
		}
		if (user.getUserCenter() == null) {
			user.setUserCenter(userCenterService.findById(user.getId()));
		}
		return user;
	}

	@Cacheable(value = "accountCache", key = "#username")
	@Override
	public SysUser findByUsername(String username) {
		logger.info("real querying account... {}", username);
		SysUser user = userRepository.findByUsernameOne(username);
		if (user == null) {
			return null;
		}
		if (user.getUserInfo() == null) {
			user.setUserInfo(userInfoService.findById(user.getId()));
		}
		if (user.getUserCenter() == null) {
			user.setUserCenter(userCenterService.findById(user.getId()));
		}
		return user;
	}

	@CacheEvict(value = "accountCache", key = "#entity.getId()")
	@Transactional
	@Override
	public SysUser edit(SysUser entity) {
		logger.info("entity:" + entity.toString());
		return super.edit(entity);
	}

	@CacheEvict(value = "accountCache", key = "#form.getId()")
	@Transactional
	@Override
	public SysUser edit(UserForm form) {
		logger.info("form:" + form.toString());
		if (form.getPassword() != null && form.getPassword().equals("****")) {
			form.setPassword(null);
			return super.edit(form);
		}
		if (form.getPassword() != null && !form.getPassword().equals("****")) {
			SysUser obj = getRepository().findOne(form.getId());
			traversalAssign(form, obj);
			encryptPassword(obj);
			return super.edit(obj);
		}
		return null;
	}

	@Transactional
	@Override
	public SysUser add(UserForm form) {
		SysUser exUser = findByUsername(form.getUsername());
		if (exUser != null) {
			throw Global.getException(userException.getRegUserExist());
		}
		exUser = new SysUser();
		traversalAssign(form, exUser);
		SysUser user = add(exUser);
		return user;
	}

	@Transactional
	@Override
	public SysUser add(SysUser entity) {
		SysUser exUser = findByUsername(entity.getUsername());
		if (exUser != null) {
			throw Global.getException(userException.getRegUserExist());
		}
		encryptPassword(entity);
		entity.setCreatedDate(new Date());// DateTime.now());
		SysUser user = super.add(entity);
		return user;
	}

	@Autowired
	private RetryLimitHashedCredentialsMatcher credentialsMatcher;
	private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();

	public void encryptPassword(SysUser user) {
		user.setSalt(randomNumberGenerator.nextBytes().toHex());
		String newPassword = new SimpleHash(
				credentialsMatcher.getHashAlgorithmName(), user.getPassword(),
				ByteSource.Util.bytes(user.getCredentialsSalt()),
				credentialsMatcher.getHashIterations()).toHex();

		user.setPassword(newPassword);
	}

	private boolean isExist(SysUser sysUser) {
		return userRepository.findByUsernameOne(sysUser.getUsername()) != null;
	}

	@Transactional
	@Override
	public boolean sendSms(UserForm form) {
		SysUser user = userRepository.findByUsernameOne(form.getUsername());
		switch (form.getOperateType()) {
		case register:
			if (user != null) {
				throw Global.getException(userException.getRegUserExist());
			}
			verifyCodeService.register(form);
			break;
		case restPwd:
			if (user == null) {
				throw Global.getException(userException.getResetUserUnExist());
			}
			verifyCodeService.restPwd(form);
			break;
		default:
			break;
		}

		// saveSms(entity);// 应该先存储再发送
		/*
		 * if (entity.getFlag() == null) { throw
		 * Global.getException("sms.flag.unseting"); }
		 */
		// if (entity.getFlag().equals("2")) {// 1短信验证码2语音验证码
		/*
		 * HttpUtils.voiceSingleSend(Global.voiceConfig, entity.getUsername(),
		 * verifyCode);
		 */

		// } else {
		/*
		 * String mes = String.format(Global.smsContent, entity.getZType()
		 * .getTitle(), verifyCode);
		 * HttpUtils.smsSingleSend(Global.singleConfig, entity.getUsername(),
		 * mes);
		 */

		// }

		return true;

	}

	@Override
	public Class<SysUser> getEntityClazz() {
		return SysUser.class;
	}

	@Override
	public Map<String, SearchFilter> buildByForm(UserForm form) {
		Map<String, SearchFilter> filters = buildFilter();

		if (form.getUsername() != null && !form.getUsername().equals("")) {
			filters.put("username", new SearchFilter("username", Operator.EQ,
					form.getUsername()));
		}
		if (form.getNickname() != null && !form.getNickname().equals("")) {
			filters.put("nickname", new SearchFilter("nickname", Operator.LIKE,
					form.getNickname()));
		}
		/*
		 * if (form.getUserType() != null) { filters.put("userType", new
		 * SearchFilter("userType", Operator.EQ, form.getUserType().ordinal()));
		 * }
		 */
		if (form.getRoleId() != null) {
			filters.put("mainRole.id", new SearchFilter("mainRole.id",
					Operator.EQ, form.getRoleId()));
		}
		return filters;
	}

	//

	@Override
	public List<SysUser> findUnUsersByRoleId(Long roleId) {
		return userRepository.findUnUsersByRoleId(roleId);
	}

	@Override
	public List<SysUser> findUsersByRoleId(Long roleId) {

		return userRepository.findUsersByRoleId(roleId);
	}

	@Transactional
	@Override
	public void update(Observable o, Object arg) {
		if (o instanceof RegisterService) {
			RegisterService userRegisterService = (RegisterService) o;
			if (arg instanceof UserForm) {
				UserForm userForm = (UserForm) arg;
				if (!userForm.isCreate()) {
					throw Global.getException("新增用户失败，请联系管理员");
				}
				/*
				 * if (!userRegisterService.isEfficacyCode()) {// 效验码正确 throw
				 * Global.getException(userException .getVerifyCodeError()); }
				 * SysUser user = BeanMapper.map(userForm, SysUser.class);
				 * user.setUserType(UserTypeEnum.normal);
				 * user.setOnlineFlag(true); user.setStatus(UserEnum.lock);
				 */
				SysUser user = add(userForm);
				userForm.setUser(user);
			}
		}
		if (o instanceof LoginService) {
			BaseUser baseUser = userUtils.getUser();
			if (baseUser != null) {// 用户已登录，自动绑定账号
				return;
			}
			LoginService userLoginService = (LoginService) o;
			SysUser user = new SysUser();
			if (arg instanceof QQToken) {

				QQToken upToken = (QQToken) arg;
				QQUser qqUser = upToken.getQqUser();
				// QQUser qqUser = qqUserService.findById(qqUserForm.getId());
				if (qqUser.getUser() == null) {
					String qqUserName = "QQ" + Utils.nextInt(1000, 9999);
					user.setUsername(qqUserName);
					user.setPassword(qqUserName);
					// user.setUsername(upToken.getOpenId());
					// user.setPassword(upToken.getAccessToken());
					// user.setUserType(UserTypeEnum.normal);
					user.setMainRole(upToken.getMainRole());
					user.setOnlineFlag(true);
					user.setRegType(UserRegTypeEnum.qq);
					user = userRepository.save(user);
					qqUser.setUser(user);
					qqUserService.edit(qqUser);
				} else {
					user = qqUser.getUser();
					user.setOnlineFlag(true);
					user = userRepository.saveAndFlush(user);
				}
				userLoginService.setUser(user);
			}
			if (arg instanceof WxAppToken) {
				WxAppToken upToken = (WxAppToken) arg;
				WxUser wxUser = upToken.getWxUser();
				// QQUser qqUser = qqUserService.findById(qqUserForm.getId());
				if (wxUser.getUser() == null) {
					user = new SysUser();
					String wxUserName = "WX" + Utils.nextInt(1000, 9999);
					user.setUsername(wxUserName);// wxUser.getNickname());//
													// "微信用户"
					// + Global.wxUserCount.incrementAndGet());
					user.setPassword(wxUserName);
					// user.setUserType(UserTypeEnum.normal);
					user.setRegType(UserRegTypeEnum.weixin);
					user.setOnlineFlag(true);
					user.setMainRole(upToken.getMainRole());
					user = userRepository.save(user);
					wxUser.setUser(user);
					wxUserService.edit(wxUser);
				} else {
					user = wxUser.getUser();
					user.setOnlineFlag(true);
					user = userRepository.saveAndFlush(user);
				}
				userLoginService.setUser(user);
				upToken.setUser(user);
			}
		}
	}

	@Transactional
	@Override
	public SysUser editPwd(UserForm form) {
		SysUser exUser = userRepository.findOne(form.getId());
		if (exUser == null) {
			throw Global.getException(userException.getUserUnExist());
		}
		exUser.setPassword(form.getPassword());
		encryptPassword(exUser);
		/*
		 * if (entity.getNickname() == null || entity.getNickname().equals(""))
		 * { entity.setNickname(entity.getUsername()); }
		 */
		super.edit(exUser);
		return exUser;
	}

	@Transactional
	@Override
	public SysUser editPwdByUserName(UserForm form) {
		SysUser exUser = userRepository.findByUsernameOne(form.getUsername());
		if (exUser == null) {
			throw Global.getException(userException.getUserUnExist());
		}
		exUser.setPassword(form.getPassword());
		encryptPassword(exUser);
		/*
		 * if (entity.getNickname() == null || entity.getNickname().equals(""))
		 * { entity.setNickname(entity.getUsername()); }
		 */
		super.edit(exUser);

		return exUser;
	}

	/*
	 * @Override public int findWxUserCount() { return
	 * userRepository.findWxUserCount(); }
	 */

	@CacheEvict(value = "myMenuCache", key = "#userId")
	@Override
	public void updateUserRole(Long userId) {
		// TODO 清空userId对应的缓存
		SysUser user = findById(userId);
		logger.info("UserService： clean user[" + user.getUsername() + "] roles");
	}

	@Transactional
	@Override
	public void onLogout(Long userId) {
		SysUser user = findById(userId);
		user.setOnlineFlag(false);
		super.edit(user);
	}

	@Transactional
	@Override
	public void setRole(Long userId, SysRole role) {
		SysUser user = findById(userId);
		user.setMainRole(role);
		super.edit(user);
	}

}
